/*********************************************************************************
 * SIMPLE LISTS, A SIMPLE C LIBRARY FOR LINKED LISTS.
 * Copyright (C) 2012 Fabian Ström
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2.0, as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *********************************************************************************/

#include "lists.h"

struct list_cell *list_getNext(struct list_cell *cell) 
{
	if (cell != NULL) {
		return cell->next;
	} else {
		return NULL;
	}
}

struct list_cell *list_getLast(struct list_cell *lst) 
{
	if (lst->next == NULL) {
		return lst;
	} else {
		return list_getLast(list_getNext(lst));
	}
}

struct list_cell *list_newCell()
{
	struct list_cell *cell = malloc(sizeof(struct list_cell));
	cell->next = NULL;
	return cell;
}

struct list_cell *list_createListOfSize(int size)
{
	if (size < 1)
		return NULL;
	int i = 1;
	struct list_cell *head, *curr, *prev;
	head = list_newCell();
	prev = head;
	while (i++<size) {
		curr = list_newCell();
		list_join(prev, curr);
		prev = curr;
	}
	return head;
}

struct list_cell *list_getNth(struct list_cell *lst, int n)
{
	if (n >= 0 && lst != NULL && n <= list_listLength(lst)-1) {
		return list_getNthHelper(lst, n, 0);
	} else {
		return NULL;
	}
}

struct list_cell *list_getNthHelper(struct list_cell *lst, int max, int pos) 
{
	if (pos == max) {
		return lst;
	} else if (list_getNext(lst) != NULL) {
		return list_getNthHelper(list_getNext(lst), max, pos+1);
	} else {
		return NULL;
	}
}

void list_join(struct list_cell *lst, struct list_cell *cell) 
{
	struct list_cell *last = list_getLast(lst);
	last->next = cell;
	return;
}

void list_removeCellAfter(struct list_cell *cell)
{
	free(list_getNext(cell));
	cell->next = NULL;
	return;
}

void list_deleteList(struct list_cell *cell) 
{
	struct list_cell *next = list_getNext(cell);
	if (next == NULL) {
		free(cell);
	} else {
		list_deleteList(next);
	}
	return;
}

int list_listLength(struct list_cell *list) {
	if (list == NULL) {
		return -1;
	} else {
		return list_listLengthHelper(list, 0);
	}
}

int list_listLengthHelper(struct list_cell *list, int pos) {
	if (list == NULL) {
		return pos;
	} else {
		return list_listLengthHelper(list_getNext(list), pos+1);
	}
}

void list_map(struct list_cell *lst, void (*func)(struct list_cell *cell))
{
	if (lst == NULL) {
		return;
	} else {
		(*func)(lst);
		list_map(list_getNext(lst), func);
	}
	return;
}
